#ifndef _MARK_MPSC_QUEUE_H
#define _MARK_MPSC_QUEUE_H

#include <atomic>
#include <utility>

// 非侵入式的多生产者单消费者队列
template<typename T>
class MPSCQueueNonIntrusive
{
public:
    MPSCQueueNonIntrusive() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed))
    {
        Node* front = _head.load(std::memory_order_relaxed);
        front->Next.store(nullptr, std::memory_order_relaxed);
    }

    ~MPSCQueueNonIntrusive()
    {
        T* output;
        while (Dequeue(output))
            delete output;

        Node* front = _head.load(std::memory_order_relaxed);
        delete front;
    }

    void Enqueue(T* input)
    {
        Node* node = new Node(input);
        Node* prevTail = _tail.exchange(node, std::memory_order_acq_rel);
        prevTail->Next.store(node, std::memory_order_release);
    }

    bool Dequeue(T*& result)
    {
        Node* head = _head.load(std::memory_order_relaxed);
        Node* next = head->Next.load(std::memory_order_acquire);
        if (!next)
            return false;

        result = next->Data;
        _head.store(next, std::memory_order_release);
        delete head;
        return true;
    }


private:
    struct Node
    {
        Node() = default;
        explicit Node(T* data) : Data(data)
        {
            Next.store(nullptr, std::memory_order_relaxed);
        }

        T* Data;
        std::atomic<Node*> Next;
    };

    std::atomic<Node*> _head;
    std::atomic<Node*> _tail;

    MPSCQueueNonIntrusive(MPSCQueueNonIntrusive const&) = delete;
    //我们大多数人习惯按下面的方式写
    // MPSCQueueNonIntrusive(const MPSCQueueNonIntrusive &) = delete;
    MPSCQueueNonIntrusive& operator=(MPSCQueueNonIntrusive const&) = delete;
};


// 侵入式的多生产者单消费者队列
// 侵入式链表/队列要求被入队的类型 T 自身包含用于链路的成员（比如 next 指针）。队列直接操作 T 内的这个成员，
// 而不是为每个元素额外分配一个 Node 包裹数据（非侵入式需要额外的 Node）。
template<typename T, std::atomic<T*> T::* IntrusiveLink>
class MPSCQueueIntrusive
{
public:
    MPSCQueueIntrusive() : _dummyPtr(reinterpret_cast<T*>(std::addressof(_dummy))), _head(_dummyPtr), _tail(_dummyPtr)
    {
        // _dummy is constructed from aligned_storage and is intentionally left uninitialized (it might not be default constructible)
        // so we init only its IntrusiveLink here
        std::atomic<T*>* dummyNext = new (&(_dummyPtr->*IntrusiveLink)) std::atomic<T*>();
        dummyNext->store(nullptr, std::memory_order_relaxed);
    }

    ~MPSCQueueIntrusive()
    {
        T* output;
        while (Dequeue(output))
            delete output;
    }

    void Enqueue(T* input)
    {
        (input->*IntrusiveLink).store(nullptr, std::memory_order_release);
        T* prevHead = _head.exchange(input, std::memory_order_acq_rel);
        (prevHead->*IntrusiveLink).store(input, std::memory_order_release);
    }

    bool Dequeue(T*& result)
    {
        T* tail = _tail.load(std::memory_order_relaxed);
        T* next = (tail->*IntrusiveLink).load(std::memory_order_acquire);
        if (tail == _dummyPtr)
        {
            if (!next)
                return false;

            _tail.store(next, std::memory_order_release);
            tail = next;
            next = (next->*IntrusiveLink).load(std::memory_order_acquire);
        }

        // next 非空表明 tail 节点后面已链上一个节点，消费者可以安全地把 tail 前移到 next 并返回原 tail 作为出队元素。
        if (next)
        {
            _tail.store(next, std::memory_order_release);
            result = tail;
            return true;
        }
        //否则
        T* head = _head.load(std::memory_order_acquire);
        // next 为 nullptr 有两种可能：1) 真正空（head==tail），
        // 2) 生产者已经交换了 head（head != tail）但还没写 prev->next（在做两步链接的中间态）。
        if (tail != head)//如果 tail != head，说明存在“生产者在路上但未完成链上写”，此时消费者不应尝试强行取，返回 false 等待生产者完成。
            return false;

        //tail==head 且 next==nullptr 时：enqueue 哨兵并重试
        Enqueue(_dummyPtr);
        next = (tail->*IntrusiveLink).load(std::memory_order_acquire);
        if (next)
        {
            _tail.store(next, std::memory_order_release);
            result = tail;
            return true;
        }
        return false;
    }

private:
    std::aligned_storage_t<sizeof(T), alignof(T)> _dummy;
    T* _dummyPtr;
    std::atomic<T*> _head;
    std::atomic<T*> _tail;

    MPSCQueueIntrusive(MPSCQueueIntrusive const&) = delete;
    MPSCQueueIntrusive& operator=(MPSCQueueIntrusive const&) = delete;
};

template<typename T, std::atomic<T*> T::* IntrusiveLink = nullptr>
using MPSCQueue = std::conditional_t<IntrusiveLink != nullptr, MPSCQueueIntrusive<T, IntrusiveLink>, MPSCQueueNonIntrusive<T>>;

#endif // MPSCQueue_h__
